package com.wa.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.wa.annotation.AllchipsLogProcessServiceType;
import com.wa.api.ILogMessageApi;
import com.wa.page.BaseLogEntity;
import com.wa.bean.BasicAllchipsLog;
import com.wa.dto.OperatorInfoDto;
import com.wa.enums.LogModuleEnum;
import com.wa.enums.LogTableEnum;
import com.wa.enums.LogTypeEnum;
import com.wa.pojo.BasicAllchipsLogPojo;
import com.wa.pojo.GenericResp;
import com.wa.pojo.User;
import com.wa.service.AbstractAllchipsLogProcessService;
import com.wa.service.IAllchipsLogHandleService;
import com.wa.util.CommUtils;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 平台日志处理 -- 实现类
 *
 * @author: Homan Liang
 * @time: 2021/10/22 16:50
 */
@Builder
@Slf4j
@Service
public class AllchipsLoghandleServiceImpl implements IAllchipsLogHandleService {
    @Resource
    private ILogMessageApi logMessageApi;
//    @Resource
//    private IUserInfoApi userInfoApi;

    private Map<Integer, AbstractAllchipsLogProcessService> allchipsLogProcessServiceMap;

    @Autowired
    public void setBasicAllchipsLogServiceMap(List<AbstractAllchipsLogProcessService> allchipsLogProcessServiceList) {
        allchipsLogProcessServiceMap = allchipsLogProcessServiceList.stream().collect(
                Collectors.toMap(t -> AnnotationUtils.findAnnotation(t.getClass(), AllchipsLogProcessServiceType.class).logCategory(),
                        v -> v, (v1, v2) -> v1));
    }

    /**
     * 保存日志
     *
     * @param dataObject
     * @param operatorInfoDto
     * @param logModule
     * @param logTypeEnums
     * @throws Exception
     */
    @Override
    public void saveLog(Object dataObject, OperatorInfoDto operatorInfoDto, LogModuleEnum logModule, LogTypeEnum[] logTypeEnums) throws Exception {
        // 构建日志信息
        List<BasicAllchipsLogPojo> basicAllchipsLogPojos = this.buildLog(dataObject, operatorInfoDto, logModule, logTypeEnums);
        if (CollectionUtils.isEmpty(basicAllchipsLogPojos)){
            return;
        }
        // 保存日志信息
        GenericResp genericResp = logMessageApi.sendLogMsg(basicAllchipsLogPojos);
        if (log.isInfoEnabled()) {
            log.info("-----------------------日志发送完成，{}", JSONUtil.toJsonStr(genericResp));
        }
    }

    /**
     * 保存日志--异步调用
     *
     * @param dataObject
     * @param operatorInfoDto
     * @param logModule
     * @param logTypeEnums
     * @throws Exception
     */
    @Override
    public void saveLogAsync(Object dataObject, OperatorInfoDto operatorInfoDto, LogModuleEnum logModule, LogTypeEnum[] logTypeEnums) throws Exception {
        try {
            new Thread(() -> {
                try {
                    this.saveLog(dataObject, operatorInfoDto, logModule, logTypeEnums);
                } catch (Exception e) {
                    log.error("异步调用==saveLog==异常：", e);
                }
            }).start();
        } catch (Exception ex) {
            log.error("saveLogAsyn==异常：", ex);
        }
    }

    /**
     * 保存日志--异步调用
     *
     * @param dataObject
     * @param operatorInfoDto
     * @param logModule
     * @param logTypeEnum
     * @throws Exception
     */
    @Override
    public void saveLogAsync(Object dataObject, OperatorInfoDto operatorInfoDto, LogModuleEnum logModule, LogTypeEnum logTypeEnum) throws Exception {
        try {
            new Thread(() -> {
                try {
                    LogTypeEnum[] logTypeEnums = new LogTypeEnum[1];
                    logTypeEnums[0] = logTypeEnum;
                    this.saveLog(dataObject, operatorInfoDto, logModule, logTypeEnums);
                } catch (Exception e) {
                    log.error("异步调用==saveLog==异常：", e);
                }
            }).start();
        } catch (Exception ex) {
            log.error("saveLogAsyn==异常：", ex);
        }
    }

    /**
     * 获取操作员信息
     *
     * @Author Dawn
     * @Date 2021/10/21 16:24
     */
    @Override
    public OperatorInfoDto getOperatorInfo() {
        OperatorInfoDto operatorInfoDto = new OperatorInfoDto();
        try {
            operatorInfoDto.setCreateTime(new Date());

            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            operatorInfoDto.setCreateIp(CommUtils.getRealRemoteIP(request));

            // 登录用户信息
            User user = this.getSessionBackendUser(request);
            if (user != null){
                operatorInfoDto.setCreateUserId(user.getUserId());
                /*operatorInfoDto.setCreateUserName(BackendUtil.getUserName(user));*/
                operatorInfoDto.setCreateUserEmail(user.getEmail());
            }
        } catch (Exception e) {
            log.error("getOperatorInfo异常：", e);
        }
        return operatorInfoDto;
    }


    /**
     * 获取登录用户信息
     * @Author Dawn
     * @Date 2021/10/21 15:41
     */
    private User getSessionBackendUser(HttpServletRequest request) {
        //获取登录信息
//        String sessionID = Cookies.get(request, CommonBackendConstant.SESSION_ID) ;
//        if(CommUtils.isEmpty(sessionID)) {
//            return null;
//        }
        User user = null;
//        GenericResp<BackendUserPojo> resp = userInfoApi.getSessionUserBySId(sessionID);
//        if(null != resp){
//            BackendUserPojo userPojo = resp.getData();
//            if(userPojo != null){
//                user = userPojo.getUser();
//            }
//        }
        return user;
    }

    /**
     * 构建日志信息
     *
     * @param dataObject
     * @param operatorInfoDto
     * @param logModule
     * @param logTypeEnums
     * @return
     * @throws Exception
     */
    private List<BasicAllchipsLogPojo> buildLog(Object dataObject, OperatorInfoDto operatorInfoDto, LogModuleEnum logModule
            , LogTypeEnum[] logTypeEnums) throws Exception {
        List<BasicAllchipsLogPojo> basicAllchipsLogPojos = new ArrayList<>();

        List<Object> toDoParamList = new ArrayList<>();
        // 获取待处理的日志参数对象
        if (dataObject instanceof BaseLogEntity) {
            BaseLogEntity baseLogEntity = BaseLogEntity.class.cast(dataObject);

            if (baseLogEntity != null && CollUtil.isNotEmpty(baseLogEntity.getChangeLogObjectList())) {
                toDoParamList.addAll(baseLogEntity.getChangeLogObjectList());
            } else {
                toDoParamList.add(dataObject);
            }
        } else {
            toDoParamList.add(dataObject);
        }

        for (LogTypeEnum logType: logTypeEnums) {
            for (Object object : toDoParamList) {
                // 构建日志信息
                BasicAllchipsLogPojo basicAllchipsLogPojo = this.buildBasicLogInfo(object, operatorInfoDto, logModule, logType);
                if (basicAllchipsLogPojo != null){
                    basicAllchipsLogPojos.add(basicAllchipsLogPojo);
                }
            }
        }

        return basicAllchipsLogPojos;
    }

    /**
     * 构建日志信息
     *
     * @param dataObject
     * @param operatorInfoDto
     * @param logModule
     * @param logType
     * @return
     * @throws Exception
     */
    private BasicAllchipsLogPojo buildBasicLogInfo(Object dataObject, OperatorInfoDto operatorInfoDto
            , LogModuleEnum logModule, LogTypeEnum logType) throws Exception {
        BasicAllchipsLogPojo basicAllchipsLogPojo = new BasicAllchipsLogPojo();
        // 根据类型分配当前日志需存储的日志表信息
        LogTableEnum logTableEnum = LogTableEnum.getLogTableEnum(logType, logModule);
        if (logTableEnum == null){
            log.error("********************************存储日志信息时，分配日志表失败，模块：{}|{}，类型：{}|{}"
                    , logModule.getStatusCode(), logModule.getStatusMsgCn(), logType.getStatusCode(), logType.getStatusMsgCn());
            return null;
        }
        basicAllchipsLogPojo.setLogTableEnum(logTableEnum);
        basicAllchipsLogPojo.setLogModuleEnum(logModule);

        // 日志信息处理
        AbstractAllchipsLogProcessService abstractAllchipsLogProcessService = allchipsLogProcessServiceMap.get(logType.getCategoryCode());
        if (CommUtils.isNotNull(abstractAllchipsLogProcessService)) {
            abstractAllchipsLogProcessService.processLog(dataObject, basicAllchipsLogPojo, operatorInfoDto);
        }
        // 设日志设置相关信息
        this.setLogSettingInfo(basicAllchipsLogPojo, logModule, logType);

        return basicAllchipsLogPojo;
    }

    /**
     * 设日志设置相关信息
     *
     * @param basicAllchipsLogPojo
     * @param logModule
     * @param logType
     * @throws Exception
     */
    private void setLogSettingInfo(BasicAllchipsLogPojo basicAllchipsLogPojo, LogModuleEnum logModule, LogTypeEnum logType) throws Exception {
        List<BasicAllchipsLog> basicAllchipsLogList = basicAllchipsLogPojo.getBasicAllchipsLogs();
        if (CollectionUtils.isEmpty(basicAllchipsLogList)) {
            return;
        }
        for (BasicAllchipsLog basicAllchipsLog : basicAllchipsLogList) {
            if (CommUtils.isNull(basicAllchipsLog)) {
                continue;
            }
            basicAllchipsLog.setModule(logModule.getStatusCode());
            basicAllchipsLog.setPlatform(logModule.getPlatformCode());
            basicAllchipsLog.setType(logType.getStatusCode());
        }
    }
}
